import json
import logging
import os
import baostock as bs
from scipy import stats

import matplotlib.pyplot as plt

from stockChooseBigA import send_mail_and_message
from typing import Optional, Tuple, List
import adata
from Indicators.macd import *

# 设置字体支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 'SimHei' 是黑体，你可以根据系统安装的字体更改
plt.rcParams['axes.unicode_minus'] = False  # 正确显示负号

from tqdm import tqdm
import threading
import matplotlib
# matplotlib.use('Agg')  # 在文件顶部全局设置非交互式后端

class StockAnalyzer:
    def __init__(self, tickers):
        self.tickers = tickers
        self.results = []
        # 初始化线程锁
        self.plot_lock = threading.Lock()

    @staticmethod
    def calculate_volatility_stats(data: pd.DataFrame,
                                   lookback: int = 120) -> Tuple[float, float]:
        """
        改进的波动率计算方法
        返回：(当日波动率, 历史百分位)
        """
        try:
            # 计算对数收益率
            returns = np.log(data['close']).diff().dropna()

            # 计算滚动波动率（年化）
            rolling_vol = returns.rolling(window=20).std() * np.sqrt(252)

            # 获取有效数据
            valid_vol = rolling_vol.dropna()[-lookback:]  # 取指定周期的波动率数据

            if len(valid_vol) < 20:
                return (np.nan, np.nan)

            # 当日波动率
            current_vol = valid_vol.iloc[-1]

            # 计算历史百分位
            percentile = stats.percentileofscore(valid_vol.values, current_vol)

            return (current_vol, percentile)

        except Exception as e:
            print(f"波动率计算错误: {str(e)}")
            return np.nan, np.nan

    def process_stock(self, name: str,ticker: str) -> Optional[dict]:
        """线程安全的股票处理方法"""
        try:
            res_df = adata.stock.market.get_market(stock_code=ticker, k_type=1, start_date='2024-10-01')
            if res_df.empty:
                return None
            value = 0
            try:
                value = adata.stock.info.get_stock_shares(stock_code=ticker).loc[0,'total_shares'] * res_df.at[res_df.index[-1],'close']/100000000
            except:
                pass
            if "ST" in name:
                return None
            # 获取行业分类数据
            industry = ''
            # try:
            #     rs = bs.query_stock_industry(c_stock_code)
            #     concept = ",".join(adata.stock.info.get_concept_ths(stock_code=ticker)['name'])
            #
            #     industry = rs.data[0][3] + concept
            # except:
            #     industry = ""
            if len(res_df) < 30:  # 至少需要30个交易日数据
                return None

            # 初始化分析器
            analyzer = SupportResistanceAnalyzer(data=res_df,bin_width=0.03)

            # 获取信号和指标
            signal, sr_ratio, dist_ratio,nearest_resistance, nearest_support= analyzer.is_buy_signal(p=1.2,q=1.2)
            if not signal:
                return None

            fig_save_path = os.path.join(pic_dir,"{}.png".format(name))
            fig_save_path_radar = os.path.join(pic_dir, "{} 雷达图.png".format(name))

            analyzer.plot(title="{} 支撑压力分析".format(name),save_path=fig_save_path)
             # 生成信号强度图

            analyzer.plot_signal_strength(dark_mode=False,title="{} 雷达图".format(name),save_path=fig_save_path_radar)

            # 计算波动率指标
            vol, percentile = self.calculate_volatility_stats(res_df)

            if np.isnan(vol) or np.isnan(percentile):
                return None

            return {
                '代码': ticker,
                '名称': name,
                '压力支撑比': sr_ratio,
                '距离比率': dist_ratio,
                '当前价格': analyzer.current_price,
                '市值': "{}".format(value),
                '当日波动率': vol,
                '波动率百分位': percentile,
            }

        except Exception as e:
            print(f"处理 {ticker} 时发生错误: {str(e)}")
            return None

    def run_screening(self, output_path: str = 'stock_signals.csv',
                      max_workers: int = 8,
                      timeout: int = 10):
        """
        多线程优化版股票筛选

        参数：
        max_workers : 最大并发线程数 (建议4-16)
        timeout : 单个股票处理超时时间（秒）
        """
        results = []

        print(f"开始多线程筛选{len(self.tickers)}只股票（线程数：{max_workers}）...")

        # 使用进度条包装器
        # with tqdm(total=len(self.tickers)) as pbar:
        #     with ThreadPoolExecutor(max_workers=max_workers) as executor:
        #         # 创建任务字典 {future: ticker}
        #         future_to_ticker = {
        #             executor.submit(self.process_stock, ticker,stockname): ticker
        #             for stockname, ticker in self.tickers
        #         }
        #
        #         # 按完成顺序处理结果
        #         for future in as_completed(future_to_ticker, timeout=timeout):
        #             ticker = future_to_ticker[future]
        #             try:
        #                 result = future.result()
        #                 if result:
        #                     results.append(result)
        #             except Exception as e:
        #                 print(f"\n处理 {ticker} 时发生错误: {str(e)}")
        #             finally:
        #                 pbar.update(1)

        # """执行全市场筛选

        print(f"开始筛选{len(self.tickers)}只股票...")
        for sname,ticker in tqdm(self.tickers):
            result = self.process_stock(ticker,sname)
            if result:
                results.append(result)

        # 后续处理与保存（与原有逻辑相同）
        df = pd.DataFrame(results)

        # 添加筛选条件状态
        df['符合条件'] = '是'

        df = df[[
            '代码', '名称', '当前价格',
            '压力支撑比', '距离比率', '当日波动率','波动率百分位', '符合条件','市值'
        ]]

        # 保存结果
        df.to_csv(output_path, index=False, encoding='utf-8-sig')
        print(f"结果已保存至 {output_path}，共找到 {len(df)} 只符合条件的股票")
        return df



class SupportResistanceAnalyzer:
    def __init__(self,
                 ticker: Optional[str] = None,
                 start_date: Optional[str] = None,
                 end_date: Optional[str] = None,
                 data: Optional[pd.DataFrame] = None,
                 bin_width: float = 0.02):
        """
        支撑压力位分析器

        参数：
        ticker: 股票代码（使用yfinance格式）
        start_date: 数据开始日期（YYYY-MM-DD）
        end_date: 数据结束日期
        data: 可直接提供包含OHLCV数据的DataFrame
        bin_width: 价格区间宽度（按百分比计）
        """
        if data is not None:
            self.data = data
        else:
            raise ValueError("必须提供ticker或data参数")

        self.bin_width = bin_width
        self.price_bins: np.ndarray = None
        self.volume_dist: np.ndarray = None
        self.support_levels: List[float] = []
        self.resistance_levels: List[float] = []
        self.current_price: float = self.data['close'].iloc[-1]

        # 执行计算流程
        self._compute_price_bins()
        self._compute_volume_distribution()
        self._find_key_levels()

    def _compute_price_bins(self) -> None:
        """计算价格区间"""
        price_min = self.data[['low', 'close']].min().min()
        price_max = self.data[['high', 'close']].max().max()
        price_range = price_max - price_min

        # 动态计算区间数量
        bin_size = price_min * self.bin_width
        num_bins = max(int(price_range / bin_size), 10)  # 确保至少有10个区间

        # 扩展5%的范围防止边缘情况
        self.price_bins = np.linspace(price_min * 0.95,
                                      price_max * 1.05,
                                      num=num_bins)

    def _compute_volume_distribution(self) -> None:
        """计算成交量在价格区间的分布"""
        distribution = np.zeros(len(self.price_bins) - 1)

        for _, row in self.data.iterrows():
            low, high, vol = row['low'], row['high'], row['volume']
            price_range = high - low or 1e-6  # 防止零除

            # 找到覆盖的价格区间
            start_idx = np.searchsorted(self.price_bins, low, side='left')
            end_idx = np.searchsorted(self.price_bins, high, side='right')

            for bin_idx in range(start_idx, end_idx):
                if bin_idx >= len(self.price_bins) - 1:
                    continue

                bin_low = self.price_bins[bin_idx]
                bin_high = self.price_bins[bin_idx + 1]

                # 计算重叠部分比例
                overlap_low = max(low, bin_low)
                overlap_high = min(high, bin_high)
                overlap_ratio = (overlap_high - overlap_low) / price_range

                distribution[bin_idx] += vol * overlap_ratio

        self.volume_dist = distribution

    def _find_key_levels(self, n_levels: int = 5) -> None:
        """识别关键支撑/压力位并记录成交量强度"""
        sorted_indices = np.argsort(self.volume_dist)[::-1]
        bin_width = self.price_bins[1] - self.price_bins[0]

        self.support_levels = []  # 存储元组(price, strength)
        self.resistance_levels = []

        for idx in sorted_indices:
            level = (self.price_bins[idx] + self.price_bins[idx + 1]) / 2
            strength = self.volume_dist[idx]

            # 去重检查
            existing_levels = [x[0] for x in self.support_levels + self.resistance_levels]
            if any(abs(level - x) < bin_width for x in existing_levels):
                continue

            if level < self.current_price:
                if len(self.support_levels) < n_levels:
                    self.support_levels.append((level, strength))
            else:
                if len(self.resistance_levels) < n_levels:
                    self.resistance_levels.append((level, strength))

            if len(self.support_levels) >= n_levels and len(self.resistance_levels) >= n_levels:
                break

        # 按价格排序
        self.support_levels.sort(key=lambda x: x[0], reverse=True)
        self.resistance_levels.sort(key=lambda x: x[0])

    def plot_bollinger(self, ax=None):
        """绘制布林带辅助判断"""
        if ax is None:
            ax = plt.gca()

        mid = self.data['close'].rolling(20).mean()
        std = self.data['close'].rolling(20).std()
        upper = mid + 2 * std
        lower = mid - 2 * std

        ax.plot(mid, label='中轨', color='blue', alpha=0.5)
        ax.fill_between(mid.index, upper, lower, color='gray', alpha=0.2)
        # ax.set_title('布林带走势', fontsize=10)


    def plot(self, figsize: Tuple[int, int] = (14, 10),
             title: Optional[str] = None,
             save_path: Optional[str] = None,
             label_position: str = 'left') -> plt.Figure:
        """可视化带强度颜色的支撑压力位"""
        """可视化方法优化版"""
        # 创建带比例控制的子图
        fig, (ax1, ax2) = plt.subplots(
            2, 1,
            figsize=figsize,
            gridspec_kw={'height_ratios': [3, 1]},  # 调整高度比例为3:1
            sharex=True
        )

        # 设置默认标题
        default_title = f"{getattr(self, 'ticker', '证券')} 支撑压力位分析"
        final_title = title if title else default_title

        # ========== 绘制主图 ==========
        ax1.set_title(final_title, fontsize=14, pad=20)  # 使用最终标题



        # 创建颜色映射
        sup_strengths = [x[1] for x in self.support_levels]
        res_strengths = [x[1] for x in self.resistance_levels]
        all_strengths = sup_strengths + res_strengths
        norm = plt.Normalize(min(all_strengths), max(all_strengths))

        # 价格走势图
        # ax1 = plt.subplot(2, 1, 1)
        ax1.plot(self.data['close'], label='Close Price')

        # 获取坐标轴范围
        x_min, x_max = ax1.get_xlim()
        y_min, y_max = ax1.get_ylim()

        # 自动确定标签偏移量
        y_range = y_max - y_min
        label_offset = y_range * 0.02  # 2%的价格范围作为偏移


        def add_label(ax, level, strength, color):
            """智能添加价格标签（修复版）"""
            # 动态确定标签位置
            pos_options = []
            x_min, x_max = ax.get_xlim()
            y_range = ax.get_ylim()[1] - ax.get_ylim()[0]
            label_offset = y_range * 0.02  # 2%的价格范围作为偏移

            # 生成候选位置（修复坐标生成逻辑）
            if label_position in ['right', 'both']:
                pos_options.append((x_max, level, 'right'))  # (x坐标, y坐标, 对齐方式)
            if label_position in ['left', 'both']:
                pos_options.append((x_min, level, 'left'))

            for x_pos, y_pos, ha in pos_options:
                # 修复坐标转换逻辑：确保每次处理单个坐标点
                try:
                    # 将数据坐标转换为显示坐标
                    display_coords = ax.transData.transform((x_pos, y_pos))
                except ValueError as e:
                    print(f"坐标转换错误 x={x_pos}, y={y_pos}: {str(e)}")
                    continue

                # 检测标签重叠（修复版）
                overlap = False
                for child in ax.get_children():
                    if isinstance(child, plt.Text):
                        # 获取现有标签的显示坐标范围
                        bbox = child.get_window_extent()
                        if bbox.contains(*display_coords):
                            overlap = True
                            break

                if not overlap:
                    # 动态调整标签位置
                    text_y = y_pos + (label_offset if y_pos < self.current_price else -label_offset)

                    # 添加文本标注（显式指定数值类型）
                    ax.text(
                        x=x_pos,
                        y=text_y,
                        s=f"{float(y_pos):.2f}",  # 确保转换为float
                        color=color,
                        ha=ha,
                        va='bottom' if y_pos < self.current_price else 'top',
                        fontsize=8 + 4 * norm(strength),
                        bbox=dict(
                            facecolor='white',
                            alpha=0.7,
                            edgecolor=color,
                            boxstyle='round,pad=0.2'
                        ),
                        transform=ax.transData  # 显式指定坐标变换
                    )
                    break

        # 绘制支撑位
        for level, strength in self.support_levels:
            color = plt.cm.Greens(norm(strength))
            ax1.axhline(level, color=color, linestyle='--',
                        linewidth=1 + 2 * norm(strength),  # 线宽反映强度
                        alpha=0.8, label='Support')
            add_label(ax1, level, strength, color)

        # 绘制压力位
        for level, strength in self.resistance_levels:
            color = plt.cm.Reds(norm(strength))
            ax1.axhline(level, color=color, linestyle='--',
                        linewidth=1 + 2 * norm(strength),
                        alpha=0.8, label='Resistance')
            add_label(ax1, level, strength, color)

        # 绘制布林带
        self.plot_bollinger(ax1)
        # ========== 颜色条优化 ==========
        # 支撑颜色条（左侧）
        cax_sup = fig.add_axes([0.12, 0.92, 0.2, 0.02])  # [左, 下, 宽, 高]
        plt.colorbar(
            plt.cm.ScalarMappable(cmap=plt.cm.Greens, norm=norm),
            cax=cax_sup,
            orientation='horizontal',
            label='支撑强度'
        )
        cax_sup.xaxis.set_ticks_position('top')
        cax_sup.xaxis.set_label_position('top')

        # 压力颜色条（右侧）
        cax_res = fig.add_axes([0.68, 0.92, 0.2, 0.02])
        plt.colorbar(
            plt.cm.ScalarMappable(cmap=plt.cm.Reds, norm=norm),
            cax=cax_res,
            orientation='horizontal',
            label='压力强度'
        )
        cax_res.xaxis.set_ticks_position('top')
        cax_res.xaxis.set_label_position('top')

        # ========== 成交量图优化 ==========
        # 计算成交量颜色映射（根据收盘价变化）
        colors = np.where(self.data['close'].diff() >= 0, 'g', 'r')
        ax2.bar(self.data.index, self.data['volume'],
               color=colors, alpha=0.6, width=0.8)

        # 设置成交量图参数
        ax2.set_ylabel('成交量', fontsize=9)
        ax2.tick_params(axis='both', labelsize=8)
        ax2.grid(axis='y', alpha=0.3)

        plt.tight_layout(pad=2.0, h_pad=0.5)  # 增加子图间距

        # ========== 保存图片 ==========
        if save_path:
            try:
                plt.savefig(save_path, bbox_inches='tight', dpi=300)
                # print(f"图表已保存至：{save_path}")
                plt.close()
            except Exception as e:
                print(f"保存失败：{str(e)}")
        return fig

    def is_buy_signal(self, p: float = 1.0,q:float = 1.0) -> Tuple[bool, float, float,any,any]:
        """
        完整使用 support_levels/resistance_levels 二元数组结构的版本
        """
        # 初始化默认返回值
        ratio_strength = float('inf')
        ratio_distance = 0.0
        conditions = []
        has_resistance = len(self.resistance_levels) > 0
        has_support = len(self.support_levels) > 0

        nearest_resistance = None
        nearest_support = None

        try:
            # === 基础数据校验 ===
            if len(self.data) < 20:
                return (False, ratio_strength, ratio_distance,None,None)

            # === 条件1：布林带中轨斜率 ===
            mid_band = self.data['close'].rolling(20, min_periods=1).mean().values
            if len(mid_band) < 2 or np.isnan(mid_band[-2:]).any():
                return (False, ratio_strength, ratio_distance,None,None)

            slope = float(mid_band[-1] - mid_band[-2])
            conditions.append(slope > 0)

            # === 条件2：当日收盘价上涨 ===
            close_prices = self.data['close'].values
            price_rise = bool(close_prices[-1] > close_prices[-2]) if len(close_prices) >= 2 else False
            conditions.append(price_rise)

            # === 条件3：处于支撑位之上 ===
            if has_support:
                # 从二元数组中提取价格
                support_prices = [level[0] for level in self.support_levels]
                valid_supports = [p for p in support_prices if p < self.current_price]
                if valid_supports:
                    strongest_support = max(valid_supports)
                    above_support = self.current_price > strongest_support
                else:
                    above_support = False
                conditions.append(above_support)
            else:
                conditions.append(False)

            # === 压力支撑强度比 ===
            if has_resistance and has_support:
                total_support = sum(level[1] for level in self.support_levels)
                total_resist = sum(level[1] for level in self.resistance_levels)
                ratio_strength = total_support / total_resist if total_resist != 0 else 0
                conditions.append(float(ratio_strength) > p)
            else:
                # 无压力位时自动满足强度条件
                conditions.append(True) if not has_resistance else conditions.append(False)

            # === 价格距离比 ===
            if has_resistance and has_support:
                # 提取压力位价格
                resist_prices = [level[0] for level in self.resistance_levels]
                valid_resist = [p for p in resist_prices if p > self.current_price]

                # 提取支撑位价格
                support_prices = [level[0] for level in self.support_levels]
                valid_supports = [p for p in support_prices if p < self.current_price]

                if valid_resist and valid_supports:
                    nearest_resist = min(valid_resist)
                    nearest_support = max(valid_supports)
                    resist_dist = nearest_resist - self.current_price
                    support_dist = self.current_price - nearest_support
                    ratio_distance = resist_dist / support_dist if support_dist != 0 else float('inf')
                    conditions.append(ratio_distance > q)
                else:
                    # 当存在有效压力位但无有效支撑位时视为不满足
                    conditions.append(False)
            else:
                # 无压力位时自动满足距离条件
                conditions.append(True) if not has_resistance else conditions.append(False)
                if has_support:
                    # 提取支撑位价格
                    support_prices = [level[0] for level in self.support_levels]
                    valid_supports = [p for p in support_prices if p < self.current_price]
                    nearest_support = max(valid_supports)
                if has_resistance:
                    # 提取压力位价格
                    resist_prices = [level[0] for level in self.resistance_levels]
                    valid_resist = [p for p in resist_prices if p > self.current_price]
                    nearest_resist = min(valid_resist)


            # 放量上涨
            if self.data['volume'].iloc[-1] > self.data['volume'].iloc[-2] * 1.1:
                conditions.append(True)

        except Exception as e:
            print(f"信号计算异常: {str(e)}")
            return (False, ratio_strength, ratio_distance, nearest_resistance, nearest_support)

        return (all(conditions), ratio_strength, ratio_distance, nearest_resistance, nearest_support)

    def plot_signal_strength(self,
                             title: Optional[str] = None,
                             save_path: Optional[str] = None,
                             figsize=(8, 8), dark_mode=False):
        """
        信号强度雷达图可视化
        """
        # 获取信号组件数据
        components = self._get_signal_components()

        # 创建图表
        fig = plt.figure(figsize=figsize)
        ax = fig.add_subplot(111, polar=True)

        # 雷达图参数设置
        labels = ['布林带斜率', '价格上涨', '支撑强度', '压力强度比', '距离比']
        num_vars = len(labels)

        # 角度计算
        angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
        angles += angles[:1]  # 闭合图形

        # 数据处理
        values = [
            components['slope_strength'],
            components['price_rise_strength'],
            components['support_strength'],
            components['strength_ratio_strength'],
            components['distance_ratio_strength']
        ]
        values += values[:1]  # 闭合图形

        # 绘制雷达图
        ax.plot(angles, values, linewidth=2, linestyle='solid', color='#1f77b4')
        ax.fill(angles, values, color='#1f77b4', alpha=0.25)

        # 坐标轴设置
        ax.set_theta_offset(np.pi / 2)
        ax.set_theta_direction(-1)
        ax.set_rlabel_position(0)

        # 标签和标题
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(labels, fontsize=10)

        # 设置默认标题
        default_title = "信号强度雷达图\n"
        final_title = title if title else default_title

        ax.set_title(final_title, fontsize=12, pad=20)

        # 极径范围标准化
        ax.set_ylim(0, 1)

        # 暗色模式支持
        if dark_mode:
            plt.style.use('dark_background')
            ax.set_facecolor('#2e2e2e')
            ax.tick_params(colors='white')
            ax.spines['polar'].set_color('white')
            ax.title.set_color('white')

        plt.tight_layout()

        # ========== 保存图片 ==========
        if save_path:
            try:
                # 将保存操作提交到主线程队列
                plt.savefig(save_path, bbox_inches='tight', dpi=300)
                # print(f"图表已保存至：{save_path}")
                plt.close()
            except Exception as e:
                print(f"保存失败：{str(e)}")
        return fig

    def _get_signal_components(self):
        """
        获取信号强度组件数据
        """
        components = {}

        try:
            # 布林带斜率强度（标准化到0-1）
            mid_band = self.data['close'].rolling(20, min_periods=1).mean()
            slope = mid_band.iloc[-1] - mid_band.iloc[-2]
            components['slope_strength'] = min(max(slope / 0.05, 0), 1)  # 假设0.05为显著斜率

            # 价格上涨强度（布尔转0/1）
            components['price_rise_strength'] = 1.0 if self.data['close'].iloc[-1] > self.data['close'].iloc[-2] else 0.0

            # 支撑强度（当前价与最强支撑位的强度比）
            if self.support_levels:
                strongest_support = max([level[0] for level in self.support_levels], default=0)
                support_strength = next((level[1] for level in self.support_levels
                                         if level[0] == strongest_support), 0)
                current_strength = sum(1 for level in self.support_levels
                                       if level[0] < self.current_price)
                components['support_strength'] = min(current_strength / 5, 1)  # 假设最多5个有效支撑
            else:
                components['support_strength'] = 0.0

            # 压力强度比（标准化）
            if self.support_levels and self.resistance_levels:
                total_support = sum(level[1] for level in self.support_levels)
                total_resist = sum(level[1] for level in self.resistance_levels)
                ratio = total_support / total_resist if total_resist != 0 else 1
                components['strength_ratio_strength'] = min(ratio, 1)
            else:
                components['strength_ratio_strength'] = 0.0

            # 距离比（标准化）
            if self.support_levels and self.resistance_levels:
                valid_resist = [level[0] for level in self.resistance_levels
                                if level[0] > self.current_price]
                valid_support = [level[0] for level in self.support_levels
                                 if level[0] < self.current_price]
                if valid_resist and valid_support:
                    resist_dist = min(valid_resist) - self.current_price
                    support_dist = self.current_price - max(valid_support)
                    ratio = support_dist / resist_dist if resist_dist != 0 else 1
                    components['distance_ratio_strength'] = min(ratio, 1)   # 标准化到0-1
                else:
                    components['distance_ratio_strength'] = 0.0
            else:
                if self.support_levels:
                    components['distance_ratio_strength'] = 1.0
                else:
                    components['distance_ratio_strength'] = 0.0

        except Exception as e:
            print(f"信号组件获取失败: {str(e)}")
            return {k: 0.0 for k in ['slope_strength', 'price_rise_strength',
                                     'support_strength', 'strength_ratio_strength',
                                     'distance_ratio_strength']}

        return components


    @property
    def key_levels(self) -> dict:
        """获取带强度的关键价位"""
        return {
            'current_price': self.current_price,
            'support': sorted(self.support_levels, key=lambda x: -x[0]),
            'resistance': sorted(self.resistance_levels, key=lambda x: x[0])
        }





if __name__ == '__main__':

    # param test's value is False if is True will use simulate trading

    base_dir = r"./"
    n = 3 # 看多少跟K线的最低价低于

    with open(os.path.join(base_dir, "passwords", "passwords.json"), 'r') as f:
        data = json.load(f)

    # 登陆系统
    lg = bs.login()
    # 显示登陆返回信息
    print('login respond error_code:' + lg.error_code)
    print('login respond  error_msg:' + lg.error_msg)
    #
    # # 获取A500指数成分股列表
    # # 获取中证500成分股
    # rs = bs.query_zz500_stocks()
    # print('query_zz500 error_code:' + rs.error_code)
    # print('query_zz500  error_msg:' + rs.error_msg)
    #
    # # 打印结果集
    # zz500_stocks = []
    # while (rs.error_code == '0') & rs.next():
    #     # 获取一条记录，将记录合并在一起
    #     zz500_stocks.append(rs.get_row_data())

    # 获取全部股票代码
    # 设置代理,代理是全局设置,代理失效后可重新设置。参数:ip,proxy_url
    adata.proxy(is_proxy=True, ip='127.0.0.1:10810')
    res_df = adata.stock.info.all_code()
    # 组合 exchange 和 stock_code 成 "SZ.00001" 形式的列表
    # 创建字典，将exchange和stock_code组合成key，short_name作为value
    combined_map = {f"{row['exchange']}.{row['stock_code']}": row['short_name'] for index, row in res_df.iterrows()}



    # 设置日志存储位置
    LOG_DIR = os.path.join(base_dir, "./log")
    if not os.path.exists(LOG_DIR):
        os.makedirs(LOG_DIR)
    LOG_ADDR = os.path.join(LOG_DIR, 'chooseLogA.log')
    logging.basicConfig(filename=LOG_ADDR,format='%(asctime)s - %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
    logger = logging.getLogger(__name__)
    logger.info("start")
    logger.info(combined_map)

    # 图片保存位置
    pic_dir = os.path.join(base_dir, "./pictures")
    if not os.path.exists(pic_dir):
        os.makedirs(pic_dir)
    all_stock_list = []
    stock_code = "600986"
    res_df = adata.stock.market.get_market(stock_code=stock_code, k_type=1, start_date='2024-10-01')

    # 示例1：使用在线数据
    analyzer = SupportResistanceAnalyzer(
        data=res_df,
        bin_width=0.03
    )
    print("支撑位：", analyzer.support_levels)
    print("压力位：", analyzer.resistance_levels)
    # 获取信号数据
    signal, strength_ratio, distance_ratio,_,_ = analyzer.is_buy_signal(p=0.8)

    # 生成信号强度图
    fig = analyzer.plot_signal_strength(dark_mode=False)
    plt.show()

    # 结果解读
    print(f"""
    买入信号状态：{'满足' if signal else '不满足'}
    压力支撑强度比：{strength_ratio:.2f}
    价格距离比率：{distance_ratio:.2f}
    当前价格：{analyzer.current_price:.2f}
    有效支撑位：{[level[0] for level in analyzer.support_levels if level[0] < analyzer.current_price]}
    有效压力位：{[level[0] for level in analyzer.resistance_levels if level[0] > analyzer.current_price]}
    """)
    analyzer.plot(title="{} 支撑压力分析".format(stock_code))
    plt.show()

    # 筛选
    # 使用 map 函数将字典转换为键值对的迭代器
    # key_value_pairs = map(lambda item: (item[0].split(".")[1], item[1]), combined_map.items())
    # # 将 map 对象转换为二维数组
    # key_value_list = list(key_value_pairs)
    #
    # # 初始化参数
    # tickers = key_value_list
    # output_file = 'selected_stocks.csv'
    #
    # try:
    #     # 创建分析器实例
    #     analyzer = StockAnalyzer(
    #         tickers=tickers
    #     )
    #
    #     # 执行多线程筛选（设置8个并发线程，单个股票超时10秒）
    #     result_df = analyzer.run_screening(
    #         output_path=output_file,
    #         max_workers=8,
    #         timeout=10
    #     )
    #
    #     # 打印简要结果
    #     if not result_df.empty:
    #         print("\n筛选结果摘要：")
    #         print(f"找到符合条件股票 {len(result_df)} 只")
    #
    #         print("\n完整结果已保存至：", output_file)
    #     else:
    #         print("本次筛选未找到符合条件的股票")
    #
    # except Exception as e:
    #     print(f"主程序运行异常: {str(e)}")
    # finally:
    #     print("股票筛选流程结束")


    # for c_stock_code, name in combined_map.items():
    #     stock_code = c_stock_code.split(".")[1]
    #     if  name in all_stock_list:
    #         continue
    #     res_df = adata.stock.market.get_market(stock_code=stock_code, k_type=1, start_date='2024-10-01')
    #     try:
    #         info_df = adata.stock.info.get_industry_sw(stock_code=stock_code)
    #     except:
    #         pass
    #     if res_df.empty:
    #         continue
    #
    #     # try:
    #     #     value = adata.stock.info.get_stock_shares(stock_code=stock_code).loc[0,'total_shares'] * res_df.at[res_df.index[-1],'close']/100000000
    #     #     if value > 500:
    #     #         continue
    #     # except:
    #     #     pass
    #     # 获取行业分类数据
    #     industry = ''
    #     try:
    #         rs = bs.query_stock_industry(c_stock_code)
    #         concept = ",".join(adata.stock.info.get_concept_ths(stock_code=stock_code)['name'])
    #
    #         industry = rs.data[0][3] + concept
    #     except:
    #         industry = ""
    #
    #     analyzer = SupportResistanceAnalyzer(
    #         data=res_df,
    #         bin_width=0.03
    #     )
    #     # 获取信号数据
    #     signal, strength_ratio, distance_ratio = analyzer.is_buy_signal(p=0.8)
    #
    #     if signal:
    #         print("支撑位：", analyzer.support_levels)
    #         print("压力位：", analyzer.resistance_levels)
    #         fig_save_path = os.path.join(pic_dir,"{}.png".format(name))
    #         fig_save_path_radar = os.path.join(pic_dir, "{} 雷达图.png".format(name))
    #         analyzer.plot(title="{} 支撑压力分析".format(name),save_path=fig_save_path)
    #         # 生成信号强度图
    #         analyzer.plot_signal_strength(dark_mode=False,title="{} 雷达图".format(name),save_path=fig_save_path_radar)
    #
    #         all_stock_list.append(name)
    #         send_mail_and_message(res_df,industry,c_stock_code,name)
    #     print(name,signal,"\n")

